package com.sie.zhq.module;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.sie.algorithm.sm.SM2keyPair;
import com.sie.algorithm.sm.SMUtil;
import com.sie.zhq.bean.APDU_RESP;
import com.sie.zhq.bean.APDU_SEND;
import com.sie.zhq.bean.IdentityInfo317Bean;
import com.sie.zhq.constconfig.ConstDefine;
import com.sie.zhq.constconfig.ErrorDefine;
import com.sie.zhq.tool.ByteTool;
import com.sie.zhq.tool.StringUtil;
import com.sie.zhq.tool.Timer;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static android.text.TextUtils.isEmpty;


/**
 * Created by zhq on 2016/6/24.
 */
public class DeviceInterface {
    public final static String THREE_DES_MODE = "30";
    public final static String DES_MODE = "20";
    public final static String SM4_MODE = "80";
    public final static String SM4_MODE_MAIN = "90";
    public final static String TAG = "DeviceInterface";
    public static IDCardModule identityModule = IDCardModule.getInstance();
//    public static CipherKeyBoardModule keyBoardModule = CipherKeyBoardModule.getInstance();

    public static UsbSerialKMYCipher keyBoardModule = UsbSerialKMYCipher.getInstance();

    public static FinancialModule financialModule = FinancialModule.getInstance();

    public static CallBackHandler handler = new CallBackHandler();
    /**
     * 模块独立线程池所有操作通过线程池保证先入先出
     */
    private static ExecutorService executorService = Executors.newFixedThreadPool(1);

    private static FinancialThread financialThread = null;

    private static ExecutorService keyThreadPool = Executors.newFixedThreadPool(1);
    public static TesoFingerprintModule tesoFingerPrintModule = TesoFingerprintModule.getInstance();
    public static FingerPrintRunnable fingerPrintRunnable = null;
    private static ExecutorService fingerThreadPool = Executors.newFixedThreadPool(1);
    public static int getFingerFeature(final DeviceCallback callback, int timeOutMs, final boolean isOnMain) {



        if (fingerPrintRunnable != null) {
            fingerPrintRunnable.stopRun();
            fingerPrintRunnable = null;
        }
        fingerPrintRunnable = new FingerPrintRunnable(FingerPrintRunnable.Action.READ_FEATURE, callback, timeOutMs, isOnMain);
        fingerThreadPool.execute(fingerPrintRunnable);

        return 0;
    }
    public static int getFingerPic(final DeviceCallback callback, int timeOutMs, final boolean isOnMain) {
        /**
         *
         * usb 指纹模块
         */
        if (callback == null) {

            return ErrorDefine.NO_CALLBACK;
        }
        if (fingerPrintRunnable != null) {
            fingerPrintRunnable.stopRun();
            fingerPrintRunnable = null;
        }
        fingerPrintRunnable = new FingerPrintRunnable(FingerPrintRunnable.Action.GET_PIC, callback, timeOutMs, isOnMain);
        fingerThreadPool.execute(fingerPrintRunnable);
        return 0;
    }


    /**
     * 身份证和密码键盘均为单线程，会先终结当前线程再起
     */
    public static IdModuleThread idModuleThread = null;

    public static InputPassWordThread inputThread = null;


    private final static int START = 0;
    private final static int SUCCESS = 1;
    private final static int ERROR = 2;
    private final static int COMPLETED = 3;

    public static enum Result {

        START, SUCCEED, ERROR, COMPLETED

    }

    public static SM2keyPair getSM2keypair() {
        SM2keyPair keypair = SMUtil.generatorSm2KeyPair();

        return keypair;
    }

    public static byte[] SM2Decipher(String prvk, String content, int mode) {
        if (prvk.length() > 0) {
            byte[] buf = SMUtil.SM2PrvDecrypt(prvk, content, mode);
            return buf;
        }
        return null;

    }

    /**
     * 初始化键盘
     *
     * @param context
     */
    public static void initPWDInput(Context context) {

        keyBoardModule.setContext(context);


    }

    /**
     * 获取唯一标识
     *
     * @param context
     * @return
     */
    public static String getDeviceId(Context context) {
        StringBuilder deviceId = new StringBuilder();
        // 渠道标志
//        deviceId.append("a");
        try {
            //wifi mac地址
            WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            WifiInfo info = wifi.getConnectionInfo();
            String wifiMac = info.getMacAddress();
            if (!isEmpty(wifiMac)) {
//                deviceId.append("wifi");
                deviceId.append(wifiMac);
                Log.e("getDeviceId : ", deviceId.toString());
                return deviceId.toString();
            }
            //IMEI（imei）
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            String imei = tm.getDeviceId();
            if (!isEmpty(imei)) {
//                deviceId.append("imei");
                deviceId.append(imei);
                Log.e("getDeviceId : ", deviceId.toString());
                return deviceId.toString();
            }
            //序列号（sn）
            String sn = tm.getSimSerialNumber();
            if (!isEmpty(sn)) {
//                deviceId.append("sn");
                deviceId.append(sn);
                Log.e("getDeviceId : ", deviceId.toString());
                return deviceId.toString();
            }

        } catch (Exception e) {
            e.printStackTrace();

        }
        Log.e("getDeviceId : ", deviceId.toString());
        return deviceId.toString();
    }


    public static boolean checkLampLink() {

        String serialDev = ConstDefine.ID_PORT;

        return new File(serialDev).exists();

    }



    /**
     * 升级金融板固件
     *
     * @param fileName
     * @param callback
     * @param isOnMain
     */
    public static void updateFw(String fileName, final DeviceCallback callback, boolean isOnMain) {

        FwUpdateModule module = new FwUpdateModule();
        try {
            module.readFile(fileName);
        } catch (IOException e) {

            e.printStackTrace();
        }
        module.setCallback(callback, isOnMain);
        module.startDownload();


    }

    /**
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int autoCardInfo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.AUTO_READ_CARD_INFO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    public static int ARPCExecuteScript(int ICType, String ARPC, String ScriptStr,
                                        byte[] ScriptResult, byte[] TC) {
        byte[] RspCode = null;
        byte[] AuthCode = "123456".getBytes();
        int AuthCodeLen = 0;
        byte ucResult = 0;
        byte[] IAuthData = new byte[8];
        byte[] Script = null;
        int IAuthDataLen = 0;
        int ScriptLen = 0;
        byte[] Result = new byte[1024];
        int[] RetLen = new int[1];
        int ret = -1;
        try {
            int nIndex = ARPC.indexOf("91");
            if (nIndex != -1) {
                String substr = ARPC.substring(nIndex + 2,
                        nIndex + 4);
                IAuthDataLen = Integer.parseInt(substr, 16);
                Log.e(TAG, "IAuthDataLen = " + IAuthDataLen);
                IAuthData = StringUtil.hexStringToBytes(ARPC.substring(nIndex + 4, nIndex + 4 + IAuthDataLen * 2));
                Log.e(TAG, "IAuthData = " + ByteTool.bytearrayToHexString(IAuthData, IAuthDataLen));
                RspCode = StringUtil.hexStringToBytes(ARPC.substring(nIndex + 4 + IAuthDataLen * 2 - 4, nIndex + 4 + IAuthDataLen * 2));
                Log.e(TAG, "RspCode = " + ByteTool.bytearrayToHexString(RspCode, 2));
            }
            nIndex = ScriptStr.indexOf("72");
            if (nIndex != -1) {
                String substr = ScriptStr.substring(nIndex + 2,
                        nIndex + 4);
                ScriptLen = Integer.parseInt(substr, 16) + 2;
                Log.e(TAG, "ScriptLen = " + ScriptLen);
                Script = StringUtil.hexStringToBytes(ScriptStr.substring(nIndex, nIndex + ScriptLen * 2));
                Log.e(TAG, "Script = " + ByteTool.bytearrayToHexString(Script, ScriptLen));
            } else {
                Script = new byte[0];
            }
            if (ICType == 0x00)
                ret = financialModule.EmvLib_ProcTransComplete(ucResult, RspCode, AuthCode, AuthCodeLen, IAuthData, IAuthDataLen, Script, ScriptLen);
            else if (ICType == 0x02)
                ret = financialModule.EmvLib_ProcCLTransComplete((byte) 0, RspCode, AuthCode, AuthCodeLen);
            else
                return ret;
            if (ret != 0) {
                Log.e(TAG, "EmvLib_ProcCLTransComplete: ret = " + ret);
                return ret;
            }
            ret = financialModule.EmvLib_GetScriptResult(Result, RetLen);
            if (ret != 0) {
                Log.e(TAG, "EmvLib_GetScriptResult: ret = " + ret);
                return ret;
            }
            System.arraycopy("DF31".getBytes(), 0, ScriptResult, 0, 4);
            if (RetLen[0] > 9) {
                System.arraycopy(("" + RetLen[0]).getBytes(), 0, ScriptResult, 4, 2);
            } else {
                System.arraycopy(("0" + RetLen[0]).getBytes(), 0, ScriptResult, 4, 2);
            }
            System.arraycopy(ByteTool.bytearrayToHexString(Result, RetLen[0])
                    .getBytes(), 0, ScriptResult, 6, RetLen[0] * 2);
            String[] tags = {"98"};

            byte[] dataOut = new byte[1024];
            int[] len1 = new int[1];
            ret = financialModule.EmvLib_GetTags(tags, dataOut, len1);
            byte[] out = new byte[len1[0]];
            System.arraycopy(dataOut, 0, out, 0, len1[0]);
            if (ret == 0) {
                System.arraycopy(ByteTool.bytearrayToHexString(dataOut, len1[0])
                        .getBytes(), 0, TC, 0, len1[0] * 2);
            }

        } finally {
            if (ICType == 0x00)
                financialModule.libIccClose((byte) 0x00);
            else if (ICType == 0x02)
                financialModule.libPiccClose();

        }
        return ret;

    }

    /**
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int readPicLog(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_PIC_LOG, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    /**
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int readIcLog(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_IC_LOG, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    /**
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int readPiccInfo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_PIC_INFO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    /**
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int readIcInfo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_IC_INFO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    public static void cancelFinancialThread() {

        if (financialThread != null) {
            financialThread.stopRun();
            while (true) {
                if (financialThread == null || financialThread.isFinish()) {
                    break;
                }
            }
            financialThread = null;
            financialModule.flush();
        }
    }

    /**
     * 刷磁条卡
     *
     * @param callback
     * @param timeOutMs
     * @return
     */
    public static int readMsr(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {
            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_MSR, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;
    }

    public static int autoCardNo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {

            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.AUTO_READ_CARD_NO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;

    }

    public static int readPiccCardNo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {

            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_PIC_CARD_NO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;

    }

    public static int readIcCardNo(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (financialThread != null && !financialThread.isRunFlag()) {

            return -1;
        }
        Runnable r = new Runnable() {
            @Override
            public void run() {
                cancelFinancialThread();
                financialThread = new FinancialThread(FinancialThread.READ_IC_CARD_NO, callback, timeOutMs, isOnMain);
                financialThread.start();
            }
        };
        executorService.execute(r);
        return 0;

    }

    public static void cancelInput() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                if (inputThread != null) {

                    inputThread.stopRun();

//                    while (!inputThread.isFinish()) ;

                    keyBoardModule.cancelInput();
                    keyBoardModule.flush();
                }
                inputThread = null;
            }
        }).start();

    }


    /**
     * 启动密码键盘输入
     *
     * @param cardNo
     * @param masterKeyIndex
     * @param workKeyIndex
     * @param pwdLen
     * @param timeOutSec
     * @param encryptMode
     * @param callback
     * @param isOnMain
     * @return
     */
    public static int startInputPwd(final String cardNo, final String masterKeyIndex, final String workKeyIndex, final String pwdLen, final String timeOutSec, final String encryptMode, final DeviceCallback callback, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        new Thread(new Runnable() {
            @Override
            public void run() {

                int res = setKeyEncryptMode(SM4_MODE);

                Log.e("sm4res:",res+"---");

                try {
                    if (inputThread != null) {
                        inputThread.stopRun();
//                        while (!inputThread.isFinish()) ;
                        keyBoardModule.cancelInput();
                        keyBoardModule.flush();
                    }
                    inputThread = null;
                    inputThread = new InputPassWordThread(cardNo, masterKeyIndex, workKeyIndex, pwdLen, timeOutSec, encryptMode, callback, isOnMain);
                    inputThread.start();

                } catch (NumberFormatException e) {
                    keyBoardModule.flush();
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                    bundle.putString("message", e.getMessage());
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                }
            }


        }).start();

        return 0;
    }


    public static int readIdentity(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        if (idModuleThread != null) {
            idModuleThread.stopRun();
            while (!idModuleThread.isFinish()) ;
            idModuleThread = null;
        }
        idModuleThread = new IdModuleThread(callback, timeOutMs, isOnMain);
        idModuleThread.start();
        return 0;
    }

    /**
     * 金融板上电,需要时间回调
     *
     * @param callback
     * @param isOnMain
     * @return
     */
    public static int openFinancial(final DeviceCallback callback, final boolean isOnMain) {

        boolean isOn = financialModule.PowerOn();
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        Runnable r = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    int res = -1;
                    Timer tm = new Timer(15000);
                    tm.start();
                    deliverResult(callback, Result.START, null, isOnMain);
                    SystemClock.sleep(3000);
                    while (true) {
                        if (tm.timeOut()) {
                            Log.e(TAG, "tm.timeOut!!");
                            Bundle bundle = new Bundle();
                            bundle.putInt("code", ErrorDefine.TIME_OUT);
                            bundle.putString("message", "Time out!");
                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            break;
                        }
                        byte[] bootVer = new byte[3];
                        byte[] appVer = new byte[3];
                        res = financialModule.readVersion(bootVer, appVer);
                        Log.e(TAG, "res:" + res);
                        if (res == 0) {
                            if (financialModule.EmvLib_Init() != 0) {
                                Bundle bundle = new Bundle();
                                bundle.putInt("code", ErrorDefine.EMV_INIT_ERR);
                                bundle.putString("message", "EmvLib_Init error!");
                                deliverResult(callback, Result.ERROR, bundle, isOnMain);
                                break;
                            }
                            Bundle bundle = new Bundle();
                            bundle.putByteArray("data", appVer);
                            deliverResult(callback, Result.SUCCEED, bundle, isOnMain);
                            break;
                        }
                        financialModule.flush();
                        SystemClock.sleep(100);
                    }
                    deliverResult(callback, Result.COMPLETED, new Bundle(), isOnMain);
                    Log.e(TAG, "COMPLETED");
                }
            }
        };
        executorService.execute(r);
        return isOn ? 0 : -1;
    }


    public static int icCommand(APDU_SEND apduSend, APDU_RESP apduResp) {

        return financialModule.libIccCommand((byte) 0, apduSend, apduResp);
    }

    public static int closeIcCard() {

        return financialModule.libIccClose((byte) 0);
    }

    public static int openIcCard() {
        byte[] atr = new byte[20];
        return financialModule.libIccOpen((byte) 0, (byte) 1, atr);
    }

    public static int checkIcCard() {

        return financialModule.libIccCheck((byte) 0x00);
    }


    public static boolean closeFinancial() {

        return financialModule.PowerOff();
    }


    /**
     * 注入主密钥
     *
     * @param keyIndex
     * @param keyData
     * @return
     */
    public static int inputCipherMainKey(final String keyIndex, final String keyData, final DeviceCallback callback, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        Runnable r = new Runnable() {
            @Override
            public void run() {

                deliverResult(callback, Result.START, null, isOnMain);
                byte[] check = new byte[4];
                int res = keyBoardModule.injectionMainKey(keyIndex, keyData, check);
                if (res == 0) {
                    Bundle bundle = new Bundle();
                    bundle.putString("data", ByteTool.byte2hex(check));
                    deliverResult(callback, Result.SUCCEED, bundle, isOnMain);
                } else {
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.SWIPE_ERROR);
                    bundle.putString("message", "inputCipherMainKey ERR!");
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                }
                deliverResult(callback, Result.COMPLETED, new Bundle(), isOnMain);

            }
        };
        keyThreadPool.execute(r);
        return 0;
    }


    /**
     * 注入工作密钥
     *
     * @param MainKeyIndex
     * @param workKeyIndex
     * @param workKey
     * @return
     */
    public static int inputCipherWorkKey(final String MainKeyIndex, final String workKeyIndex, final String workKey, final DeviceCallback callback, final boolean isOnMain) {
        if (callback == null)
            return ErrorDefine.NO_CALLBACK;
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int res = setKeyEncryptMode(SM4_MODE);

                Log.e("sm4res:",res+"---");
                deliverResult(callback, Result.START, null, isOnMain);
                byte[] check = new byte[4];
                res = keyBoardModule.injectionWorkKey(MainKeyIndex, workKeyIndex, workKey, check);
                if (res == 0) {
                    Bundle bundle = new Bundle();
                    bundle.putString("data", ByteTool.byte2hex(check));
                    deliverResult(callback, Result.SUCCEED, bundle, isOnMain);
                } else {
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.SWIPE_ERROR);
                    bundle.putString("message", "inputCipherWorkKey ERR!");
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                }
                deliverResult(callback, Result.COMPLETED, new Bundle(), isOnMain);

            }
        };
        keyThreadPool.execute(r);
        return 0;
    }

    /**
     * 设置密码键盘加密模式
     *
     * @return
     */
    public static int setKeyEncryptMode(final String mode) {
       Runnable runnable =  new Runnable() {
            @Override
            public void run() {
                int res;
                if (mode == DeviceInterface.SM4_MODE) {
                    Log.e("setKeyEncryptMode", "SM4");
                    res = keyBoardModule.setEncryptMode(CipherKeyBoardModule.WORK_KEY_P, mode);
                    res = keyBoardModule.setEncryptMode("05", "05");
                    return ;
                }
                if (mode == DeviceInterface.SM4_MODE_MAIN) {
                    Log.e("setKeyEncryptMode", "SM4MAIN");
                    res = keyBoardModule.setEncryptMode(CipherKeyBoardModule.WORK_KEY_P, mode);
                    res = keyBoardModule.setEncryptMode("05", "05");
                    return ;
                }
                res = keyBoardModule.setEncryptMode(CipherKeyBoardModule.MASTER_KEY_P, mode);
                if (res != 0) {
                    return ;
                }
                res = keyBoardModule.setEncryptMode(CipherKeyBoardModule.WORK_KEY_P, mode);
                res = keyBoardModule.setEncryptMode("05", "05");

            }
        };
        keyThreadPool.submit(runnable);
        return 0;

    }


    public static void closeKeyBoard() {

//        keyBoardModule.PowerOffKeyBoard();
    }

    public static void openKeyBoard() {
//        keyBoardModule.PowerOnKeyBoard();
    }


    public static void closeIdentity() {

        identityModule.PowerOffReader();
    }

    public static void openIdentity() {
        identityModule.PowerOnReader();
    }

    /**
     * 读取身份证模块编号
     *
     * @return
     */
    public static String readIdSerialNo() {
        String[] sRet = new String[1];
        byte[] sam = identityModule.ReadSAMIDBuf(sRet);
        return ByteTool.byte2hex(sam);
    }

    public static class InputPassWordThread extends Thread {
        private String cardNo;
        private String masterKeyIndex;
        private String workKeyIndex;
        private String pwdLen;
        private String timeOutSec;
        private String encryptMode;
        private DeviceCallback callback;
        private boolean isOnMain;
        private boolean pwdInputFlag = true;
        private boolean isFinish = false;

        public boolean isFinish() {

            return isFinish;
        }

        public boolean isRunning() {

            return pwdInputFlag;
        }

        public void stopRun() {

            pwdInputFlag = false;
        }

        public InputPassWordThread(String cardNo, String masterKeyIndex, String workKeyIndex, String pwdLen, String timeOutSec, String encryptMode, DeviceCallback callback, boolean isOnMain) {
            this.cardNo = cardNo;
            this.masterKeyIndex = masterKeyIndex;
            this.workKeyIndex = workKeyIndex;
            this.pwdLen = pwdLen;
            this.timeOutSec = timeOutSec;
            this.encryptMode = encryptMode;
            this.callback = callback;
            this.isOnMain = isOnMain;
        }

        @Override
        public void run() {
            //设置使用的密钥
            synchronized (this) {
                int res = keyBoardModule.setEncryptKey(masterKeyIndex, workKeyIndex);
                if (res != 0) {
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                    bundle.putString("message", "setEncryptKey err");
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                    return;
                }
                //设置卡号或传输码
                res = keyBoardModule.setCardNoOrTransCode(cardNo);
                if (res != 0) {
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                    bundle.putString("message", "setCardNoOrTransCode err");
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                    return;
                }
                res = keyBoardModule.startEncrypt(pwdLen, encryptMode, timeOutSec, "");
                if (res != 0) {
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                    bundle.putString("message", "setCardNoOrTransCode err");
                    deliverResult(callback, Result.ERROR, bundle, isOnMain);
                    return;
                }
                deliverResult(callback, Result.START, null, isOnMain);
                byte[] rspmsg = new byte[1];
                int length = Integer.valueOf(pwdLen);
                Timer timer = new Timer(Integer.valueOf(timeOutSec) * 1000);
                timer.start();
                try {
                    while (pwdInputFlag && length > 0) {

                        Log.e("length----",length+"");
                        if (timer.timeOut()) {
                            Log.e(TAG, "tm.timeOut!!");
                            Bundle bundle = new Bundle();
                            bundle.putInt("code", ErrorDefine.TIME_OUT);
                            bundle.putString("message", "Time out!");
                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            keyBoardModule.flush();
                            break;
                        }
                        int len = keyBoardModule.RecvBytes(rspmsg, 0,1, 100);
                        Log.e("pw:", ByteTool.byte2hex(rspmsg));
                        if(rspmsg[0] == 0x02){
                            byte[] pbyRecvData = new byte[256];
                           int byRet = keyBoardModule.RecvBytes(pbyRecvData, 1, 2, 200);
                            if (2 != byRet) {
                                keyBoardModule.flush();
                                Bundle bundle = new Bundle();
                                bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                                bundle.putString("message", "retry");
                                deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            }
                            byte[] lenth = new byte[2];
                            lenth[0] = pbyRecvData[1];
                            lenth[1] = pbyRecvData[2];
                            int wDataLen = Integer.parseInt(new String(lenth), 16);
                             Log.e("wDataLen", wDataLen + "===");
                            int[] pwPacketetLen = new int[1];
                            pwPacketetLen[0] = (wDataLen * 2 + 5);
                            if (wDataLen > 2176) {
                                keyBoardModule.flush();
                                Bundle bundle = new Bundle();
                                bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                                bundle.putString("message", "retry");
                                deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            }
                            byRet = keyBoardModule.RecvBytes(pbyRecvData, 3, wDataLen * 2 + 2, 500);
                            if (wDataLen * 2 + 2 != byRet) {
                                keyBoardModule.flush();
                                Bundle bundle = new Bundle();
                                bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                                bundle.putString("message", "retry");
                                deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            }
                            Log.e("RecvPacket--", ByteTool.bytearrayToHexString(pbyRecvData, pwPacketetLen[0]));
                            continue;

//                            keyBoardModule.flush();
//                            Bundle bundle = new Bundle();
//                            bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
//                            bundle.putString("message", "retry");
//                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
//                            break;
                        }
                        if (len == 0||rspmsg[0] == 0x03) {
                            continue;
                        }
                        if (rspmsg[0] == 0x1b) {
                            //取消输入直接
                            Bundle bundle = new Bundle();
                            bundle.putInt("code", ErrorDefine.CANCEL_INPUT);
                            bundle.putString("message", "取消输入");
                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            return;
                        }
                        if (rspmsg[0] == 0x08) {
                            length++;
                        } else {
                            length -= len;
                        }
                        if (rspmsg[0] == 0x0D) {
                            if (length > 0) {
                                Bundle bundle = new Bundle();
                                bundle.putInt("code", ErrorDefine.LENGTH_ERR);
                                bundle.putString("message", "pwd length error");
                                deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            } else {
                                break;
                            }
                        }
                        Log.e("length:" + length, ByteTool.byte2hex(rspmsg));
                        Bundle bundle = new Bundle();
                        bundle.putInt("flag", 1);
                        bundle.putInt("data", Integer.valueOf(pwdLen) - length);
                        deliverResult(callback, Result.SUCCEED, bundle, isOnMain);
                    }

                } finally {
                    if (pwdInputFlag) {
                        SystemClock.sleep(200);
                        byte[] buf = new byte[16];
                        int[] pwdLen = new int[1];
                        res = keyBoardModule.readEncryptPwd(buf, pwdLen);
                        Log.e("read_pwd:", ByteTool.bytearrayToHexString(buf, pwdLen[0]));
                        if (res == 0) {
                            Bundle bundle = new Bundle();
                            bundle.putInt("flag", 0);
                            bundle.putString("data", ByteTool.bytearrayToHexString(buf, pwdLen[0]));
                            deliverResult(callback, Result.COMPLETED, bundle, isOnMain);
                        } else {
                            Bundle bundle = new Bundle();
                            bundle.putInt("code", ErrorDefine.UNKNOW_ERROR);
                            bundle.putString("message", "read_pwd err");
                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
                        }
                    }
                    isFinish = true;
                }
            }

            Log.e(TAG, "COMPLETED");
        }

    }

    private static class IdModuleThread extends Thread {
        private DeviceCallback callback;
        private int timeOutMs;
        private boolean isOnMain;
        private boolean runFlag = true;

        public IdModuleThread(final DeviceCallback callback, final int timeOutMs, final boolean isOnMain) {
            this.callback = callback;
            this.timeOutMs = timeOutMs;
            this.isOnMain = isOnMain;
        }

        public void stopRun() {
            this.runFlag = false;
        }

        private boolean isFinish = false;

        public boolean isFinish() {

            return isFinish;
        }

        @Override
        public void run() {
            synchronized (this) {
                try {


                    Timer tm = new Timer(timeOutMs);
                    tm.start();
                    identityModule.PowerOnReader();
                    SystemClock.sleep(1200);
                    for (int i = 0; i < 3; i++) {
                        if (!identityModule.init()) {
                            identityModule.ReleaseReader();
                            continue;
                        }
                        break;
                    }
                    deliverResult(callback, Result.START, null, isOnMain);
                    String[] sRet = new String[1];
                    while (runFlag) {
                        if (tm.timeOut()) {
                            Log.e(TAG, "tm.timeOut!!");
                            Bundle bundle = new Bundle();
                            bundle.putInt("code", ErrorDefine.TIME_OUT);
                            bundle.putString("message", "Time out!");
                            deliverResult(callback, Result.ERROR, bundle, isOnMain);
                            break;
                        }
                        identityModule.FindCard(sRet);
                        identityModule.SelectCard(sRet);
                        IdentityInfo317Bean bean = identityModule.ReadAllCardInfo(sRet);
                        if (bean != null) {
                            Bundle bundle = new Bundle();
                            bundle.putParcelable("data", bean);
                            deliverResult(callback, Result.SUCCEED, bundle, isOnMain);
                            break;
                        }else{
                            identityModule.PowerOffReader();
                            identityModule.PowerOnReader();
                            identityModule.init();
                            identityModule.flush();
                            SystemClock.sleep(1000);
                        }

                    }
                } finally {
                    deliverResult(callback, Result.COMPLETED, new Bundle(), isOnMain);
                    identityModule.ReleaseReader();
                    isFinish = true;
                    Log.e(TAG, "COMPLETED");
                }

            }
        }
    }

    ;


    protected static synchronized void deliverResult(final DeviceCallback callback, Result result, Bundle bundle, boolean onMainThread) {
        if (onMainThread) {
            handler.setCallback(callback);
            if (result == Result.SUCCEED) {
                Message msg = new Message();
                msg.what = SUCCESS;
                msg.setData(bundle);
                handler.sendMessage(msg);
            } else if (result == Result.ERROR) {
                Message msg = new Message();
                msg.what = ERROR;
                msg.setData(bundle);
                handler.sendMessage(msg);
            } else if (result == Result.COMPLETED) {
                Message msg = new Message();
                msg.what = COMPLETED;
                msg.setData(bundle);
                handler.sendMessage(msg);
            } else if (result == Result.START) {
                Message msg = new Message();
                msg.what = START;
                handler.sendMessage(msg);
            }
        } else {
            if (result == Result.SUCCEED) {
                callback.onSuccess(bundle);
            } else if (result == Result.ERROR) {
                callback.onError(bundle);
            } else if (result == Result.COMPLETED) {
                callback.onCompleted(bundle);
            } else if (result == Result.START) {
                callback.onStart();
            }
        }

    }

    private static class CallBackHandler extends Handler {
        private DeviceCallback callback;

        public CallBackHandler() {

            super(Looper.getMainLooper());
        }

        public void setCallback(DeviceCallback callback) {
            this.callback = callback;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case START: {
                    callback.onStart();
                    break;
                }
                case SUCCESS: {
                    Bundle bundle = msg.getData();
                    callback.onSuccess(bundle);
                    break;
                }
                case ERROR: {
                    Bundle bundle = msg.getData();
                    callback.onError(bundle);
                    break;
                }
                case COMPLETED: {
                    Bundle bundle = msg.getData();
                    callback.onCompleted(bundle);
                    break;
                }
            }

        }

    }


}
